#pragma once
#include <Rz/Object.h>
#include <Rz/IEquatable.h>
#include <Rz/IHumanReadable.h>
#include <Rz/Collections/InitializerList.h>

namespace Rz { namespace Graphics { namespace Math {

class Vector3 :
	public Object,
	public IEquatable<Vector3>,
	public IHumanReadable
{
	public:
		RZ_RTTI(Rz::Graphics, Vector3);
		RZ_RTTI_IMPLEMENTS(Object, IEquatable<Vector3>, IHumanReadable);
		RZ_RTTI_END;

		union
		{
			struct { f32 X, Y, Z; };
			struct { f32 Cell[3]; };
		};

		Vector3();
		Vector3(std::initializer_list<f32> v);
		Vector3(f32 x, f32 y, f32 z);
		Vector3(const f32* ptr);
		Vector3(const Vector3& vec);

		void Set(f32 x, f32 y, f32 z);
		f32 Length() const;
		Vector3& Normalize();
		Vector3 Normalized() const;
		Vector3& Negate();
		Vector3 Negated();

		static f32 Dot(const Vector3& u, const Vector3& v);
		static f32 Distance(const Vector3& u, const Vector3& v);
		static Vector3 Cross(const Vector3& u, const Vector3& v);

		f32 operator [] (s32 index) const;
		f32& operator [] (s32 index);
		Vector3 operator + (const Vector3& vec) const;
		Vector3 operator - (const Vector3& vec) const;
		Vector3 operator * (const Vector3& vec) const;
		Vector3 operator / (const Vector3& vec) const;
		Vector3 operator + (f32 v) const;
		Vector3 operator - (f32 v) const;
		Vector3 operator * (f32 v) const;
		Vector3 operator / (f32 v) const;

		Vector3& operator += (const Vector3& v);
		Vector3& operator -= (const Vector3& v);
		Vector3& operator *= (const Vector3& v);
		Vector3& operator /= (const Vector3& v);
		Vector3& operator += (f32 v);
		Vector3& operator -= (f32 v);
		Vector3& operator *= (f32 v);
		Vector3& operator /= (f32 v);
		Vector3 operator - () const;

		friend Vector3 operator + (f32 v, const Vector3& u);
		friend Vector3 operator - (f32 v, const Vector3& u);
		friend Vector3 operator * (f32 v, const Vector3& u);
		friend Vector3 operator / (f32 v, const Vector3& u);

		// IHumanReadable
		virtual String ToString() const override;

		// IEquatable
		bool Equals(const Vector3& r) const override;

		bool operator == (const Vector3& r) const override;
		bool operator != (const Vector3& r) const override;

		static const Vector3 Zero;
		static const Vector3 One;
		static const Vector3 NormalX;
		static const Vector3 NormalY;
		static const Vector3 NormalZ;
};

} } }
